package TDengineDB

import (
	"errors"
	"fmt"
	"reflect"
	"strconv"
	"sync"
	"time"
)

//索引记录
var (
	databaseMap = sync.Map{}
	databaseLook sync.Mutex

	tableMap  = sync.Map{}
	tableLook  sync.Mutex
)

//GetTDengineClient 获取客户端
func GetTDengineClient(config map[string]string) *TDengineClient {
	ipport := config["ipport"]
	username := config["username"]
	password := config["password"]
	timeout := time.Second * 30
	if timeoutStr, ok := config["timeout"]; ok {
		atoi, err := strconv.Atoi(timeoutStr)
		if err == nil {
			timeout = time.Second * time.Duration(atoi)
		}
	}
	return NewTDengineClient(ipport, username, password, timeout)
}

// DataBaseMapping 添加映射
// @client 连接对象
// @dataName 数据库名
func DataBaseMapping(config map[string]string) *TDengineContent {
	client := GetTDengineClient(config)
	dbname := config["dbname"]
	return &TDengineContent{
		client:   client,
		database: dbname,
		config:   config,
		dbUrl:    fmt.Sprint(client.url, "#", dbname),
	}
}

//TDengineContent 数据库上下文
type TDengineContent struct {
	client   *TDengineClient   //客户端
	database string            //数据库名称
	dbUrl    string            //数据库rusfurl地址
	config   map[string]string //配置
}

//createDatabase 创建数据库
func (t *TDengineContent) createDatabase() error {
	_, ok := databaseMap.Load(t.dbUrl)
	if ok {
		return nil
	}

	databaseLook.Lock()
	defer databaseLook.Unlock()

	_, ok = databaseMap.Load(t.dbUrl)
	if ok {
		return nil
	}

	keepday, ok := t.config["keepday"]
	if !ok {
		return errors.New(fmt.Sprint("连接未配置 keepday"))
	}
	blockday, ok := t.config["blockday"]
	if !ok {
		return  errors.New("连接未配置  blockday")
	}
	blockcount, ok := t.config["blockcount"]
	if !ok {
		return  errors.New("连接未配置 blockCount")
	}

	//查看数据库是否存在
	_,err := t.client.Execute(fmt.Sprint("use ",t.database,";"))
	if err == nil {
		databaseMap.Store(t.dbUrl , true)
		//数据库存在
		return nil
	}
	//直接执行(数据库存在会异常)
	_, err = t.client.Execute(fmt.Sprint("CREATE DATABASE " , t.database , " KEEP " , keepday , " DAYS " , blockday , " BLOCKS " , blockcount , ";"))
	if err != nil {
		return  err
	}
	databaseMap.Store(t.dbUrl , true)
	return nil
}


//CreateTable 创建数据表
func (t *TDengineContent) CreateTable(entity ITDengineTable) error {
	err := t.createDatabase()
	if err != nil {
		return err
	}
	var (
		tableName string
		key       string
	)
	typeOfCat := reflect.TypeOf(entity)
	if typeOfCat.Kind() == reflect.Ptr {
		key = fmt.Sprint(t.dbUrl, "#", typeOfCat.Elem().Name())
		tableName = typeOfCat.Elem().Name()
	} else {
		key = fmt.Sprint(t.dbUrl, "#", typeOfCat.Name())
		tableName = typeOfCat.Name()
	}

	if _, ok := tableMap.Load(key); ok {
		return nil
	}
	tableLook.Lock()
	defer tableLook.Unlock()
	if _, ok := tableMap.Load(key); ok {
		return nil
	}
	_, err = t.Execute(fmt.Sprint("SELECT COUNT(TBNAME) FROM  ", t.database, ".", tableName, ";"))
	if err == nil {
		//数据库表存在
		tableMap.Store(key, true)
		return nil
	}
	value := entity.GetTagColumn()
	tag := entity.GetFieldColumn()
	//直接执行(数据表存在会异常)
	_, err = t.Execute(fmt.Sprint("CREATE STABLE ", t.database, ".", tableName, " (", value, ") TAGS (", tag, ");"))
	if err != nil {
		return err
	}
	tableMap.Store(key, true)
	return nil
}


//GetConfig 获取配置
func (t *TDengineContent) GetConfig() map[string]string {
	return t.config
}

//GetDatabase 获取数据库名称
func (t *TDengineContent) GetDatabase() string {
	return t.database
}

//Execute 执行sql
func (t *TDengineContent) Execute(sqlConn string) (*ExecuteResult,error)  {
	return t.client.Execute(sqlConn)
}

//GetTDengineRepository 获取集合仓储
// entity 结构体,columnModel列模型（"Beijng.Chaoyang", 2）
// INSERT INTO d1001 USING METERS TAGS ("Beijng.Chaoyang", 2) VALUES (now, 10.2, 219, 0.32);
func (t *TDengineContent) GetTDengineRepository(entity interface{}) ITDengineRepository {
	var entityName string
	typeOfCat := reflect.TypeOf(entity)
	if typeOfCat.Kind() == reflect.Ptr {
		entityName = typeOfCat.Elem().Name()
	} else {
		entityName = typeOfCat.Name()
	}
	return &TDengineRepository{
		database:       t.database,
		superTableName: entityName,
		client:         t.client,
	}
}
